﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using KinectFundamentals.GestureRecognizer;

namespace KinectFundamentals.GestureHandlers {
    class GestureHandler {
        private const int TimeBetweenCombinedGestures = 230;
        private const int TimeBetweenGestures = 1500;
        
        public Boolean Active = false;
        private readonly List<CombinedGesturesEnum> _combinedGestures = new List<CombinedGesturesEnum>();
        
        public List<AbstractGestureRecognizer> Recognizers = new List<AbstractGestureRecognizer>();
        public List<GestureRecognizer.GestureRecognizer> DetectedGestures = new List<GestureRecognizer.GestureRecognizer>();

        public event Action<string, JointEnum, DirectionEnum, CombinedGesturesEnum> HandlerEvent;
        private DateTime _lastEventOccured;


        public bool ActivateCombinedGesture(CombinedGesturesEnum cg) {
            if (!_combinedGestures.Contains(cg)) {
                _combinedGestures.Add(cg);
                return true;
            }
            return false;
        }

        public bool DeactivateCombinedGesture(CombinedGesturesEnum cg) {
            return _combinedGestures.Remove(cg);
        }


        public void Add(AbstractGestureRecognizer abstractGestureRecognizer) {
            Recognizers.Add(abstractGestureRecognizer);
            abstractGestureRecognizer.OnGestureDetected += OnGestureDetected;
        }

        public void Detect() {
            if (!Active) return;
            foreach (var abstractGestureRecognizer in Recognizers) {
                abstractGestureRecognizer.DetectGesture();
            }
        }

        private void OnGestureDetected(string gesture, JointEnum source, DirectionEnum direction, DateTime fromTime, DateTime toTime) {

            string eventString = gesture + " " + source + " " + direction;

            var lastGesture = new GestureRecognizer.GestureRecognizer();

            if (DetectedGestures.Count > 0) {
                lastGesture = DetectedGestures[DetectedGestures.Count - 1];
            }


            var detectedGesture = new GestureRecognizer.GestureRecognizer() {
                Gesture = gesture,
                Source = source,
                Direction = direction,
                FromTime = fromTime,
                ToTime = toTime
            };
            DetectedGestures.Add(detectedGesture);

            var detectedCombinedGesture = CombinedGesturesEnum.Empty;

            //combined gestures
            if ((detectedGesture.ToTime - lastGesture.ToTime).TotalMilliseconds < TimeBetweenCombinedGestures) {
                
                if (_combinedGestures.Contains(CombinedGesturesEnum.HandsTogether)) {
                    if (detectedGesture.Source == JointEnum.HandRight && detectedGesture.Direction == DirectionEnum.Left &&
                        lastGesture.Source == JointEnum.HandLeft && lastGesture.Direction == DirectionEnum.Right) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsTogether;
                        eventString = "Hands together, left first";
                    }

                    if (lastGesture.Source == JointEnum.HandRight && lastGesture.Direction == DirectionEnum.Left &&
                        detectedGesture.Source == JointEnum.HandLeft && detectedGesture.Direction == DirectionEnum.Right) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsTogether;
                        eventString = "Hands together, right first";
                    }
                }

                if (_combinedGestures.Contains(CombinedGesturesEnum.HandsEnlarge)) {
                    if (detectedGesture.Source == JointEnum.HandRight &&
                        detectedGesture.Direction == DirectionEnum.Right &&
                        lastGesture.Source == JointEnum.HandLeft && lastGesture.Direction == DirectionEnum.Left) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsTogether;
                        eventString = "Hands enlarge, left first";
                    }

                    if (lastGesture.Source == JointEnum.HandRight && lastGesture.Direction == DirectionEnum.Right &&
                        detectedGesture.Source == JointEnum.HandLeft && detectedGesture.Direction == DirectionEnum.Left) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsTogether;
                        eventString = "Hands enlarge, right first";
                    }
                }

                if (_combinedGestures.Contains(CombinedGesturesEnum.HandsDown)) {
                    if (lastGesture.Source == JointEnum.HandRight && lastGesture.Direction == DirectionEnum.Down &&
                        detectedGesture.Source == JointEnum.HandLeft && detectedGesture.Direction == DirectionEnum.Down) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsDown;
                        eventString = "Both hands down";
                    }

                    if (lastGesture.Source == JointEnum.HandLeft && lastGesture.Direction == DirectionEnum.Down &&
                        detectedGesture.Source == JointEnum.HandRight && detectedGesture.Direction == DirectionEnum.Down) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsDown;
                        eventString = "Both hands down";
                    }
                }

                if (_combinedGestures.Contains(CombinedGesturesEnum.HandsToScreen)) {
                    if (lastGesture.Source == JointEnum.HandLeft && lastGesture.Direction == DirectionEnum.ToScreen &&
                        detectedGesture.Source == JointEnum.HandRight &&
                        detectedGesture.Direction == DirectionEnum.ToScreen) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsToScreen;
                        eventString = "Both hands to screen";
                    }

                    if (detectedGesture.Source == JointEnum.HandLeft &&
                        detectedGesture.Direction == DirectionEnum.ToScreen &&
                        lastGesture.Source == JointEnum.HandRight && lastGesture.Direction == DirectionEnum.ToScreen) {
                        detectedCombinedGesture = CombinedGesturesEnum.HandsToScreen;
                        eventString = "Both hands to screen";
                    }
                }
            }


            double timeSinceLastGesture = (DateTime.Now - _lastEventOccured).TotalMilliseconds;
            if (timeSinceLastGesture> TimeBetweenGestures) {
                HandlerEvent(eventString, source, direction, detectedCombinedGesture);
                _lastEventOccured = DateTime.Now;
            } else {
                HandlerEvent("Ignoring: " + eventString + " - " + timeSinceLastGesture.ToString(CultureInfo.InvariantCulture), source,direction,detectedCombinedGesture);
            }
        }
    }
}
